package com.uzhie.jt808.util;

import com.uzhie.jt808.JT808Constant;
import com.uzhie.jt808.msg.JT808MsgBean;
import com.uzhie.jt808.msg.JT808MsgHeaderBean;

import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;

/**
 * Created by TangFei on 2018/7/24.
 */
public class JT808ProtocolUtil {

    private JT808ProtocolUtil() {
    }

    /**
     * 构造消息体属性
     *
     * @param msgLen
     * @param enctyptionType
     * @param isSubPackage
     * @param reversed_14_15
     * @return
     */
    public static int generateMsgBodyProps(int msgLen, int enctyptionType, boolean isSubPackage, int reversed_14_15) {
        // [ 0-9 ] 0000,0011,1111,1111(3FF)(消息体长度)
        // [10-12] 0001,1100,0000,0000(1C00)(加密类型)
        // [ 13_ ] 0010,0000,0000,0000(2000)(是否有子包)
        // [14-15] 1100,0000,0000,0000(C000)(保留位)
        int subPkg = isSubPackage ? 1 : 0;
        int ret = (msgLen & 0x3FF) | ((enctyptionType << 10) & 0x1C00) | ((subPkg << 13) & 0x2000) | ((reversed_14_15 << 14) & 0xC000);
        return ret & 0xFFFF;
    }

    /**
     * 创建消息头
     *
     * @param simNum
     * @param msgID
     * @param msgBodyProps
     * @param flowId
     * @return
     * @throws Exception
     */
    public static byte[] generateMsgHeader(String simNum, int msgID, int msgBodyProps, int flowId) throws Exception {
        ByteBuffer byteBuffer = ByteBuffer.allocate(12);
        // 1. 消息ID word(16)
        byteBuffer.put(ByteUtil.integerTo2Bytes(msgID));
        // 2. 消息体属性 word(16)
        byteBuffer.put(ByteUtil.integerTo2Bytes(msgBodyProps));
        // 3. 终端手机号 bcd[6]
        byteBuffer.put(ByteUtil.stringToBCDByteArray(simNum));
        // 4. 消息流水号 word(16),按发送顺序从 0 开始循环累加
        byteBuffer.put(ByteUtil.integerTo2Bytes(flowId));
        // 消息包封装项 暂时不用
        return byteBuffer.array();
    }


    /**
     * 转换 byte 数据类型 为 int
     *
     * @param msgBytes
     * @param pos
     * @return
     */
    public static int parseByte2Int(byte[] msgBytes, int pos) {
        return msgBytes[pos] & 0XFF;
    }

    public static short parseByte2Short(byte[] msgBytes, int pos) {
        return (short) (msgBytes[pos] & 0XFF);
    }

    /**
     * 转换 word 数据类型为 int
     *
     * @param msgBytes
     * @param pos
     * @return
     */
    public static int parseWord2Int(byte[] msgBytes, int pos) {
        return ByteUtil.parseByteArrayToInt(msgBytes, pos, 2);
    }

    /**
     * 转换 dword 数据类型为 int
     *
     * @param msgBytes
     * @param pos
     * @return
     */
    public static int parseDWord2Int(byte[] msgBytes, int pos) {
        return ByteUtil.parseByteArrayToInt(msgBytes, pos, 4);
    }

    /**
     * 转换DWord为long
     *
     * @param msgBytes 要转换的字节数组
     * @param pos      开始下标
     * @param length   截取字节长度
     * @return
     */
    public static long parseDWord2Long(byte[] msgBytes, int pos, int length) {
        ByteBuffer byteBuffer = ByteBuffer.allocate(8);
        for (int i = 0; i < 8 - length; i++) {
            byteBuffer.put((byte) 0X00);
        }
        byteBuffer.put(byteBuffer.wrap(msgBytes, pos, length));
        byteBuffer.rewind();
        return byteBuffer.getLong();
    }

    /**
     * 转换 byte[n] 数据类型 为 string
     *
     * @param msgBytes
     * @param pos
     * @param length
     * @return
     */
    public static String parseByteN2String(byte[] msgBytes, int pos, int length) {
        byte[] temp = new byte[length];
        ByteBuffer buffer = ByteBuffer.wrap(msgBytes, pos, length);
        buffer.get(temp);
        return ByteUtil.parseByteString(temp, JT808Constant.CHARSET);
    }

    /**
     * 转换 BCD[n] 数据类型为 String
     *
     * @param msgBytes
     * @param pos
     * @param length
     * @return
     */
    public static String parseBCDN2String(byte[] msgBytes, int pos, int length) {
        byte[] temp = new byte[length];
        ByteBuffer buffer = ByteBuffer.wrap(msgBytes, pos, length);
        buffer.get(temp);
        return ByteUtil.BCDByteArrayToString(temp);
    }

    /**
     * 转换808协议中的string 数据类型为 string （暂不实现）
     *
     * @param msgBytes
     * @param pos
     * @return
     */
    public String parse808String2String(byte[] msgBytes, int pos) {
        return null;
    }


    /**
     * 转换int为 byte
     *
     * @param value
     * @return
     */
    public static byte[] parseInt2Byte(int value) {
        byte[] temp = new byte[1];
        temp[0] = (byte) (value & 0xFF);
        return temp;
    }

    /**
     * 转换int 为 word
     *
     * @param value
     * @return
     */
    public static byte[] parseInt2Word(int value) {
        return ByteUtil.integerTo2Bytes(value);
    }

    /**
     * 通用应答消息体
     *
     * @param flowNumInt 流水号
     * @param msgIDInt   消息ID
     * @param result     结果
     * @return
     */
    public static byte[] commonRespBodyBytes(int flowNumInt, int msgIDInt, int result) {
        ByteBuffer byteBuffer = ByteBuffer.allocate(5);
        byteBuffer.put(parseInt2Word(flowNumInt));
        byteBuffer.put(parseInt2Word(msgIDInt));
        byteBuffer.put(parseInt2Byte(result));
        return byteBuffer.array();
    }

    /**
     * 构建808消息体
     *
     * @param msgID     消息ID
     * @param flowNum   流水号
     * @param simNum    sim卡号
     * @param bodyBytes 消息体
     * @return
     */
    public static JT808MsgBean build808Obj(int msgID, int flowNum, String simNum, byte[] bodyBytes) {
        JT808MsgBean msgBean = new JT808MsgBean();
        JT808MsgHeaderBean headerBean = new JT808MsgHeaderBean();
        headerBean.setMsgID(msgID);
        headerBean.setFlowNum(flowNum);
        headerBean.setEncrypt(0);
        headerBean.setNumSubPackage(0);
        headerBean.setTotalSubPackage(0);
        headerBean.setBodyLength(bodyBytes.length);
        headerBean.setHasSubPakage(false);
        headerBean.setSimNum(simNum);
        msgBean.setHeader(headerBean);
        msgBean.setBodyBytes(bodyBytes);
        return msgBean;
    }

    /**
     * 编码转义
     *
     * @param bytes （校验码、消息头以及消息体）
     * @return
     * @throws Exception
     */
    public static byte[] doEscapeEncode(byte[] bytes) {
        if (bytes.length < 2) {
            throw new ArrayIndexOutOfBoundsException("doEscape4Send error : 消息异常，长度过短！" + bytes.length);
        } else {
            ByteArrayOutputStream bags = new ByteArrayOutputStream();
            for (byte b : bytes) {
                switch (b) {
                    case 0X7E:
                        bags.write(0X7D);
                        bags.write(0X02);
                        break;
                    case 0X7D:
                        bags.write(b);
                        bags.write(0X02);
                        break;
                    default:
                        bags.write(b);
                        break;
                }
            }
            return bags.toByteArray();
        }
    }

    /**
     * 解码转义（转义还原）
     *
     * @param bytes （校验码、消息头以及消息体）
     * @return
     */
    public static byte[] deEscapeDecode(byte[] bytes) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        int skipIndex = -1;
        for (int i = 0; i < bytes.length; i++) {
            if (i == skipIndex) {
                continue;
            } else {
                if (i < bytes.length - 1 && bytes[i] == 0X7D && bytes[i + 1] == 0X02) {
                    byteArrayOutputStream.write(0X7E);
                    skipIndex = i + 1;
                    continue;
                }
                if (i < bytes.length - 1 && bytes[i] == 0X7D && bytes[i + 1] == 0X01) {
                    byteArrayOutputStream.write(0X7D);
                    skipIndex = i + 1;
                    continue;
                }
                byteArrayOutputStream.write(bytes[i]);
                continue;
            }
        }
        return byteArrayOutputStream.toByteArray();
    }

}
